package com.keqiang.filepicker.provider

import android.database.Cursor
import android.database.MatrixCursor
import android.net.Uri
import android.os.Environment
import android.provider.MediaStore
import android.provider.OpenableColumns
import androidx.core.content.FileProvider
import com.keqiang.filepicker.utils.MimeUtils
import java.io.File

/**
 * 自定义[FileProvider],主要就死防止与主APP AndroidManifest.xml配置的provider冲突
 *
 * @author Created by wanggaowan on 2022/5/24 13:18
 */
class FPFileProvider : FileProvider() {
    override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor {
        if (projection != null && !projection.contains(MediaStore.MediaColumns.DATA)) {
            return super.query(uri, projection, selection, selectionArgs, sortOrder)
        }

        val path =
            uri.path ?: return super.query(uri, projection, selection, selectionArgs, sortOrder)

        val context =
            context ?: return super.query(uri, projection, selection, selectionArgs, sortOrder)
        val pathSegments = uri.pathSegments
        if (pathSegments == null || pathSegments.isEmpty()) {
            return super.query(uri, projection, selection, selectionArgs, sortOrder)
        }

        try {
            val filePath: String? = if (pathSegments[0] == "fp_path1") {
                val p = Environment.getExternalStorageDirectory()?.absolutePath
                if (p == null) {
                    null
                } else {
                    path.replace("/fp_path1", p)
                }
            } else if (pathSegments[0] == "fp_path2") {
                val p = context.filesDir?.absolutePath
                if (p == null) {
                    null
                } else {
                    path.replace("/fp_path2", p)
                }
            } else if (pathSegments[0] == "fp_path2") {
                val p = context.cacheDir?.absolutePath
                if (p == null) {
                    null
                } else {
                    path.replace("/fp_path3", p)
                }
            } else if (pathSegments[0] == "fp_path0") {
                path.replace("/fp_path0", "/")
            } else {
                null
            }

            if (filePath.isNullOrEmpty()) {
                return super.query(uri, projection, selection, selectionArgs, sortOrder)
            }

            val file = File(filePath)
            val displayName = uri.getQueryParameter("displayName")
            val projectionWrapper = projection ?: COLUMNS
            var cols = arrayOfNulls<String>(projectionWrapper.size)
            var values = arrayOfNulls<Any>(projectionWrapper.size)
            var i = 0
            for (col in projectionWrapper) {
                if (OpenableColumns.DISPLAY_NAME == col) {
                    cols[i] = OpenableColumns.DISPLAY_NAME
                    values[i++] = displayName ?: file.name
                } else if (OpenableColumns.SIZE == col) {
                    cols[i] = OpenableColumns.SIZE
                    values[i++] = file.length()
                } else if (MediaStore.MediaColumns.DATA == col) {
                    cols[i] = MediaStore.MediaColumns.DATA
                    values[i++] = filePath
                } else if (MediaStore.MediaColumns.MIME_TYPE == col) {
                    cols[i] = MediaStore.MediaColumns.MIME_TYPE
                    values[i++] = MimeUtils.getFileMimeFromUrl(filePath)
                }
            }

            cols = copyOf2(cols, i)
            values = copyOf2(values, i)

            val cursor = MatrixCursor(cols, 1)
            cursor.addRow(values)
            return cursor
        } catch (e: Exception) {
            return super.query(uri, projection, selection, selectionArgs, sortOrder)
        }
    }

    companion object {
        private val COLUMNS = arrayOf(
            OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE, MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.MIME_TYPE)

        private fun copyOf2(original: Array<String?>, newLength: Int): Array<String?> {
            val result = arrayOfNulls<String>(newLength)
            System.arraycopy(original, 0, result, 0, newLength)
            return result
        }

        private fun copyOf2(original: Array<Any?>, newLength: Int): Array<Any?> {
            val result = arrayOfNulls<Any>(newLength)
            System.arraycopy(original, 0, result, 0, newLength)
            return result
        }
    }
}
